--- %%NOBANNER%% -->
/*-------------------<-- Start of Description-->---------------------\
| Binomial Equivalence Test; |
|---------------------<-- End of Description-->----------------------|
|--------------------------------------------------------------------|
|-----------<-- Start of Files or Arguements Needed-->---------------|
| Arguments: |
| This fuction take either variables from a dataset or direct |
| numbers; |
| indata: input data set; |
| ne: experiment group; |
| pe: success rate in experiment group; |
| se: count of success in experiment group; |
| nc: control group; |
| pc: success rate in control group; |
| sc: count of success in control group; |
| delta: = critical difference: |
| H0: (Control group - Experimental Group)=delta; |
| default is 0; |
| tail: = One Sided Test or Two Sided Test; |
| better:= the bigger the proportion the better, or the smaller |
| the better; BIG or SMALL: default is BIG; |
| Note: this option is required for One sided test; |
| test: HA (stands for Hauck-Anderson), BW (for Blackwelder), FM |
| (for Farrington Manning Procedure); |
| default is HA; |
| Note: the HA procedure One-Sided test will be the same as |
| BW procedure. |
| outdata: output dataset; |
|------------<-- End of Files or Arguements Needed-->----------------|
|--------------------------------------------------------------------|
|------------------<-- Start of Files Created-->---------------------|
| Example: %bnmleqv(ne=50, se=40, nc=60, sc=49,delta=0.10, test=FM, |
| tail=two, outdata=one); |
| Example 2: |
| data one; |
| success_e=70; |
| n_e=100; |
| success_c=49; |
| n_c=60; |
| run; |
| %bnmleqv(indata=one, ne=n_e, se=success_e, nc=n_c, sc=success_c, |
| test=fm, better=small, alpha=0.05, delta=0.1,tail=one); |
| Usage: %bnmleqv(indata=, ne=, pe=, se=, nc=, pc=, sc=, tail=one, |
| outdata=); |
\------------------<-- Start of Files Created-->--------------------*/
%macro bnmleqv(indata=, ne=, pe=, se=, nc=, pc=, sc=, delta=0, tail=one,
better=big,alpha=0.05,test=, outdata=);
/*--------------------------------------------\
| Author: Duo Zhou, Brian Johnson; |
| Created: 2-1-2002 7:02pm; |
| Purpose: Binomial Equivalence Test; |
\--------------------------------------------*/
%local _nnumeric_ _pnumeric_ _snumeric_ _consistence_ _i_ _grp_1 _grp_2 _linesize_ _tmplast_;
%let _tmplast_=&syslast;
%local _n1 _p1 _s1 _n2 _p2 _s2;
%let _grp_1=experimental;
%let _grp_2=control;
%let _linesize_ = %SYSFUNC(GETOPTION(linesize));
%let _n1=≠ %let _p1=&pe; %let _s1=&se; %let _n2=&nc; %let _p2=&pc; %let _s2=≻
%if (%quote(%upcase(&tail)) = ONE) or (%quote(%upcase(&tail)) = 1) %then %do;
%if (not %index(%quote(%upcase(&better)), BIG)) and (not %index(%quote(%upcase(&better)), SMALL)) %then %do;
%put ==> Alert! In order to setup the hypothesis, I need to know if the bigger the proportion;
%put +++ the better, or the smaller the proportions the better. Please specify a valid;
%put +++ option "BIGGER" or "SMALLER"!;
%end;
%end;
data _tmp1_;
retain _hyp0 hyp1 _diffSE _tvalue _pvalue;
%if &indata ne %then %do;
set &indata;
%end;
length _hyp0 _hyp1 $200.;
format _n1 _n2 _s1 _s2 Best10. default= 11.8;
%do _i_=1 %to 2;
%if (%quote(&&_n&_i_) ne) and (%quote(&&_p&_i_) ne) and (%quote(&&_s&_i_) ne) %then %do;
%if (%sysevalf(%sysevalf(&&_n&_i_*&&_p&_i_)-&&_s&_i_)>=0.5) %then %do;
%put ==> Alert! Inconsistency: (&&_n&_i_*&&_p&_i_ <> &&_s&_i_).;
%goto finish;
%end;
_n%trim(%left&_i_=&&_n&_i_;
_p&_i_=&&_p&_i_;
_s&_i_=&&_s&_i_;
%end;
%else %if (%quote(&&_n&_i_) ne) and (%quote(&&_p&_i_) ne) and (%quote(&&_s&_i_) eq) %then %do;
_n&_i_=&&_n&_i_;
_p&_i_=&&_p&_i_;
_s&_i_=(_n&_i_)*(_p&_i_);
%end;
%else %if (%quote(&&_n&_i_) ne) and (%quote(&&_p&_i_) eq) and (%quote(&&_s1) ne) %then %do;
_n&_i_=&&_n&_i_;
_s&_i_=&&_s&_i_;
_p&_i_=(_s&_i_)/(_n&_i_);
%end;
%else %if (%quote(&&_n&_i_) eq) and (%quote(&&_p&_i_) ne) and (%quote(&&_s1) ne) %then %do;
_p&_i_=&&_p&_i_;
_s&_i_=&&_s&_i_;
_n&_i_=(_s&_i_)/(_p&_i_);
%end;
%else %do;
%put ==> Alert! I will need at least 2 of the three parameters:_n&_i_,_p&_i_ and _s&_i_;
%put +++ in order to proceed.
%goto finish;
%end;
%end;
_p=(_s1+_s2)/(_n1+_n2);
%if (%quote(&test) eq) or (%quote(%upcase(&test)) eq %quote(BW)) or
%index(%quote(%upcase(&test)),%quote(BLACKWELDER)) or
(%index(%quote(%upcase(&test)),HA)) or
(%index(%quote(%upcase(&test)),%quote(HAUCK)) and
%index(%quote(%upcase(&test)),%quote(ANDERSON)))%then %do;
%if ((%index(%quote(%upcase(&test)),HA)) or (%index(%quote(%upcase(&test)),%quote(HAUCK))
and %index(%quote(%upcase(&test)),%quote(ANDERSON)))) and
((%index(%quote(%upcase(&tail)),TWO)) or (%quote(&tail) eq 2)) %then %do;
_diffSE=SQRT(_p1*(1-_p1)/(_n1-1)+_p2*(1-_p2)/(_n2-1));
%end;
%else %do;
%if (%quote(&delta) eq) or (%quote(&delta) eq %quote(0)) %then %do;
%let delta=0;
_diffSE=SQRT(_p*(1-_p)*(1/_n1+1/_n2));
%end;
%else %do;
_diffSE=SQRT(_p1*(1-_p1)/_n1+_p2*(1-_p2)/_n2);
%end;
%end;
_c=1/(2*min(_n1, _n2));
%if (%index(%quote(%upcase(&tail)),TWO)) or (%quote(&tail) eq 2) %then %do;
_hyp0="H0: |pc-pe|<=%trim(%left(&delta))"; _hyp1="Ha: |pc-pe| > %trim(%left(&delta))";
%if (%index(%quote(%upcase(&test)),HA)) or (%index(%quote(%upcase(&test)),%quote(HAUCK))
and %index(%quote(%upcase(&test)),%quote(ANDERSON))) %then %do;
_ucl = (_p1-_p2) + probit(1 - &alpha) * _diffSE + _c;
_lcl = (_p1-_p2) - probit(1 - &alpha) * _diffSE - _c;
if (1-probnorm((_p1-_p2+&delta-_c)/_diffSE)) >=(1-probnorm(abs((_p1-_p2-&delta+_c)/_diffSE)))
then _tvalue = (_p1-_p2+&delta-_c)/_diffSE;
else _tvalue=(_p1-_p2-&delta+_c)/_diffSE;
_pvalue=max((1-probnorm(abs(_p1-_p2+&delta-_c)/_diffSE)),(1-probnorm(abs((_p1-_p2-&delta+_c)/_diffSE))));
%end;
%else %do;
_lcl = (_p1-_p2) - probit(1 - &alpha/2) * _diffSE;
_ucl = (_p1-_p2) + probit(1 - &alpha/2) * _diffSE;
_tvalue = (_p1-_p2+&delta)/_diffSE;
_pvalue=(1-probnorm(abs((_p1-_p2+&delta)/_diffSE)))*2;
%end;
keep _lcl _ucl;
%end;
%else %if (%index(%quote(%upcase(&tail)),ONE)) or (%quote(&tail) eq 1) %then %do;
%if (%index(%quote(%upcase(&better)), BIG)) %then %do;
_hyp0="H0: pe <= pc-%trim(%left(&delta))"; _hyp1="Ha: pe > pc-%trim(%left(&delta))";
_tvalue=(_p1-_p2+&delta)/_diffSE;
_lcl = (_p1-_p2) - probit(1 - &alpha) * _diffSE;
_pvalue=(1-probnorm(_tvalue));
keep _lcl;
%end;
%else %if (%index(%quote(%upcase(&better)), SMALL)) %then %do;
_hyp0="H0: pe >= pc+%trim(%left(&delta))"; _hyp1="Ha: pe < pc+%trim(%left(&delta))";
_tvalue=(_p1-_p2-&delta)/_diffSE;
_ucl = (_p1-_p2) + probit(1 - &alpha) * _diffSE;
_pvalue=probnorm(_tvalue);
keep _ucl;
%end;
%end;
%end;
%else %if (%index(%quote(%upcase(&test)),FM)) or
(%index(%quote(%upcase(&test)),%quote(FARRINGTON)) and
%index(%quote(%upcase(&test)),%quote(MANNING))) %then %do;
%if (%quote(&delta) eq) or (%quote(&delta) eq %quote(0)) %then %do;
%let delta=0;
%end;
format _pi 11.8;
_pi = arcos(-1);
/* Note: the following is for "The smaller, the better"*/
/* Note: here _n1 and _n2 are all swapped from the original paper */
_theta1=_n2/_n1;
_a1 = 1 + _theta1;
_b1 = - (1 + _theta1 + _p1 + _theta1 * _p2 + &delta * (_theta1 + 2));
_c1 = &delta**2 + &delta * (2 * _p1 + _theta1 + 1) + _p1 + _theta1 * _p2;
_d1 = -_p1 * &delta * (1 + &delta);
_v1 = (_b1/(3*_a1))**3 - (_b1*_c1)/(6*(_a1**2)) + _d1/(2*_a1);
_u1 = sign(_v1)*sqrt((_b1/(3 * _a1))**2 - _c1/(3 * _a1));
_w1 = (1/3) * (_pi + arcos(_v1/_u1**3));
_p1_est1 = 2 * _u1 * cos(_w1) - _b1/(3 * _a1);
_p2_est1 = _p1_est1 - δ
_diffSE1=sqrt((_p1_est1 * (1 - _p1_est1) + (_p2_est1 * (1 - _p2_est1))/_theta1)/_n1);
/* Note: here _n1 and _n2 are all swapped from the original paper
for "The bigger, the better";
*/
_theta2=_n1/_n2;
_a2 = 1 + _theta2;
_b2 = - (1 + _theta2 + _p2 + _theta2 * _p1 + &delta * (_theta2 + 2));
_c2 = &delta**2 + &delta * (2 * _p2 + _theta2 + 1) + _p2 + _theta2 * _p1;
_d2 = -_p2 * &delta * (1 + &delta);
_v2 = (_b2/(3*_a2))**3 - (_b2*_c2)/(6*(_a2**2)) + _d2/(2*_a2);
_u2 = sign(_v2)*sqrt((_b2/(3 * _a2))**2 - _c2/(3 * _a2));
_w2 = (1/3) * (_pi + arcos(_v2/_u2**3));
_p2_est2 = 2 * _u2 * cos(_w2) - _b2/(3 * _a2);
_p1_est2 = _p2_est2 - δ
_diffSE2=sqrt((_p2_est2 * (1 - _p2_est2) + (_p1_est2 * (1 - _p1_est2))/_theta2)/_n2);
%if (%index(%quote(%upcase(&tail)),TWO)) or (%quote(&tail) eq 2) %then %do;
_hyp0="H0: |pc-pe|<=%trim(%left(&delta))"; _hyp1="Ha: |pc-pe| > %trim(%left(&delta))";
if (1-probnorm(abs((_p1-_p2+&delta)/_diffSE2)))>=(1-probnorm(abs((_p1-_p2-&delta)/_diffSE2))) then do;
_diffSE=_diffSE2;
_tvalue = (_p1-_p2+&delta)/_diffSE;
end;
else do;
_diffSE=_diffSE1; put _diffse1=;
_tvalue=(_p1-_p2-&delta)/_diffSE;
end;
_pvalue=(1-probnorm(abs((_p1-_p2+&delta)/_diffSE2)))+(1-probnorm(abs((_p1-_p2-&delta)/_diffSE1)));
_lcl = (_p1-_p2) - probit(1 - &alpha/2) * _diffSE;
_ucl = (_p1-_p2) + probit(1 - &alpha/2) * _diffSE;
keep _lcl _ucl;
%end;
%else %if (%index(%quote(%upcase(&tail)),ONE)) or (%quote(&tail) eq 1) %then %do;
%if (%index(%quote(%upcase(&better)), BIG)) %then %do;
_hyp0="H0: pe <= pc-%trim(%left(&delta))"; _hyp1="Ha: pe > pc-%trim(%left(&delta))";
_diffSE=_diffSE2;
_tvalue = (_p1-_p2+&delta)/_diffSE;
_lcl = (_p1-_p2) - probit(1 - &alpha) * _diffSE;
_pvalue=(1-probnorm(_tvalue));
keep _lcl;
%end;
%else %if (%index(%quote(%upcase(&better)), SMALL)) %then %do;
_hyp0="H0: pe >= pc+%trim(%left(&delta))"; _hyp1="Ha: pe < pc+%trim(%left(&delta))";
_diffSE=_diffSE1;
_tvalue = (_p1-_p2-&delta)/_diffSE1;
_ucl = (_p1-_p2) + probit(1 - &alpha) * _diffSE;
_pvalue=probnorm(_tvalue);
keep _ucl;
%end;
%end;
%end;
%else %do;
%put ==> Alert! I don%str(%')t recognize "&test"! I can only run "HA" (stand for "HAUCK ANDERSON") or;
%put +++ "FM" (stand for "FARRINGTON MANNING"). Please choose one test!;
%goto finish;
%end;
keep _p _tvalue _diffSE _hyp0 _hyp1 _pvalue;
label _tvalue="Test Statistics" _diffSE="Standard Error of the Proportion Difference"
_hyp0="Null Hypothesis" _hyp1="Alternative Hypothesis" _p="Overall Success Rate"
_n1="Sample size of Control Group" _p1="Success Rate in Control Group"
_n2="Sample size of Experimental Group" _p2="Success Rate in Experimental Group"
_s1="Number of Successes in Control Group" _s2="Number of Successes in Experimental Group"
_pvalue="P-Value" _lcl="Lower CI for (pc-pe)" _ucl="Upper CI for (pc-pe)";
run;
data %if (%quote(&outdata) ne) %then %do; &outdata %end; %else %do; %let syslast=&_tmplast_; _null_ %end;;
file print;
set _tmp1_;
format default=11.8;
%if (%quote(&test) eq) or (%quote(%upcase(&test)) eq %quote(BW)) or
(%index(%quote(%upcase(&test)),%quote(BLACKWELDER))) or
(%index(%quote(%upcase(&test)),HA)) or
(%index(%quote(%upcase(&test)),%quote(HAUCK)) and
%index(%quote(%upcase(&test)),%quote(ANDERSON))) %then %do;
put /;
%if (%index(%quote(%upcase(&tail)),TWO)) or (%quote(&tail) eq 2) %then %do;
%if (%index(%quote(%upcase(&test)),HA)) or (%index(%quote(%upcase(&test)),%quote(HAUCK)) and
%index(%quote(%upcase(&test)),%quote(ANDERSON))) %then %do;
put /@5 "Two-Sided Hypothesis Test on Two Proportions Using Normal Approximation with";
put @5 "Hauck-Anderson Correction";
put @5 76*"="/;
put @5 "Reference: Hauck w. w. and Andersen S.A. (1986) A comparison of large-sample"/
@5 "confidence interval methods for the difference of two binomial probabilities."/
@5 "AM Stat. VOL 40, 318-322.";
%end;
%else %do;
put /@5 "Two-Sided Hypothesis Test on Two Proportions Using Normal Approximation with";
put @5 "Blackwelder Procedure";
put @5 76*"="/;
put @5 "Reference: Blackwelder, W. C. (1982). Proving the null hypothesis in clinical"/
@5 "trials. Controlled Clinical Trials 3, 345-353.;";
%end;
%end;
%else %if ((%index(%quote(%upcase(&tail)),ONE)) or (%quote(&tail) eq 1)) %then %do;
put /@5 "One-Sided Hypothesis Test on Two Proportions Using Normal Approximation with";
put @5 "Blackwelder Procedure";
put @5 76*"="/;
put @5 "Reference: Blackwelder, W. C. (1982). Proving the null hypothesis in clinical"/
@5 "trials. Controlled Clinical Trials 3, 345-353.;";
%end;
%end;
%else %if (%index(%quote(%upcase(&test)),FM)) or (%index(%quote(%upcase(&test)),%quote(FARRINGTON MANNING)))%then %do;
%if (%index(%quote(%upcase(&tail)),TWO)) or (%quote(&tail) eq 2) %then %do;
put /@5 "Two-Sided Hypothesis Test on Two Proportions using Farrington Manning Procedure";
put @5 79*"="/;
%end;
%else %if ((%index(%quote(%upcase(&tail)),ONE)) or (%quote(&tail) eq 1)) %then %do;
put /@5 "One-Sided Hypothesis Test on Two Proportions using Farrington Manning Procedure";
put @5 79*"="/;
%end;
put @5 "Reference: Farrington, C. P. and Manning, G. (1990) Test statistics and sample"/
@5 "size formulae for comparative binomial trials with null typothesis of non-zero"/
@5 "risk difference or non-unity relative risk. Statistics in Medicine, VOL 9," /
@5 "1447-1454.";
%end;
put /;
put &_linesize_*"-";
%if (%index(%quote(%upcase(&tail)),TWO)) or (%quote(&tail) eq 2) %then %do;
put @5 "Hypothesis Test (Two Sided Test): ";
put @10 _hyp0 "vs " _hyp1 +(-1) ";"/;
%end;
%else %if ((%index(%quote(%upcase(&tail)),ONE)) or (%quote(&tail) eq 1)) and (%index(%quote(%upcase(&better)), BIG)) %then %do;
put @5 "Hypothesis Test (The Bigger, The Better!): ";
put @10 _hyp0 "vs " _hyp1 +(-1) ";"/;
%end;
%else %if ((%index(%quote(%upcase(&tail)),ONE)) or (%quote(&tail) eq 1)) and (%index(%quote(%upcase(&better)), SMALL))%then %do;
put @5 "Hypothesis Test (The Smaller, The Better!): ";
put @10 _hyp0 "vs " _hyp1 +(-1) ";"/;
%end;
put @5 "Overall Success Rate: " @35 _p 20.6 "; ";
put @5 "Standard Error (Diff): " @35 _diffSE 20.6 "; ";
put @5 "Test Statistics: " @35 _tvalue 20.6 "; ";
put @5 "P Value: " @35 _pvalue 20.6 "; "/;
put &_linesize_*"-"/;
%if (%index(%quote(%upcase(&tail)),TWO)) or (%quote(&tail) eq 2) %then %do;
put @5 "Two Sided Confidence Intervals:"/;
put @5 "%sysevalf((1-&alpha)*100)% CI for (pe-pc): (" _lcl +(-1) ", " _ucl +(-1) ").";
%end;
%else %if ((%index(%quote(%upcase(&tail)),ONE)) or (%quote(&tail) eq 1)) %then %do;
put @5 "One Sided Confidence Interval (Please choose one):"/;
%if (%index(%quote(%upcase(&better)), BIG)) %then %do;
put @5 "%sysevalf((1-&alpha)*100)% CI for (pe-pc): (" _lcl +(-1) ", +Inf).";
%end;
%else %if (%index(%quote(%upcase(&better)), SMALL)) %then %do;
put @5 "%sysevalf((1-&alpha)*100)% CI for (pe-pc): (-Inf, " _ucl +(-1) ").";
%end;
%end;
run;
proc datasets library=work nolist;
delete _tmp1_;
run;quit;
%finish:
run; quit;
%mend bnmleqv;